package org.example.timer.threadpool;

import java.util.HashSet;
import java.util.Set;

public class ThreadPool {

    private Set<Worker> workers;

    private BlockingQueue<Runnable> queue;

    private int coreSize;

    public ThreadPool(int coreSize, BlockingQueue queue, RejectPolicy policy) {
        this.coreSize = coreSize;
        this.queue = queue;
        this.rejectPolicy = policy;
        workers = new HashSet<>();
    }

    @FunctionalInterface
    public interface RejectPolicy<T> {
        void reject(BlockingQueue<T> queue, T task);
    }

    public RejectPolicy rejectPolicy;

    public class Worker implements Runnable {
        public Thread thread;

        public Runnable task;

        public Worker(Runnable task) {
            this.task = task;
            thread = new Thread(this);
        }

        @Override
        public void run() {
            while (task != null || (task = queue.get()) != null) {
                task.run();
                task = null;
            }
        }
    }

    public void execute(Runnable task) {
        if (task == null) {
            throw new NullPointerException();
        }
        if (workers.size() < coreSize) {
            Worker worker = new Worker(task);
            workers.add(worker);
            worker.thread.start();
        } else {
            queue.tryPut(task, rejectPolicy);
        }
    }
}
